import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

public class RockPaperScissors {

	/**
	 * @param args
	 */
	public static List<RPSHist> history = new LinkedList<RPSHist>();
	public static List<RPS> cHist = new LinkedList<RPS>();
	public static List<RPS> pHist = new LinkedList<RPS>();

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		java.io.PrintStream out = System.out;
		int cScore = 0;
		int pScore = 0;
		int ties = 0;
		int autoplay = 0;
		RPSHist hr = null;
		double rndVariation = .01;
		boolean debug = false;
		out.println("Welcome to Rock Paper Scissors.");
		out.println("I am going to learn how to play, so be patient.");
		while (true) {
			out.println("=========================================");
			// Computer Logic
			RPS cCurrent = RPS.values()[(int) Math.round(Math.random() * 2)];
			hr = getHistRecord();
			if (hr != null) {
				double pRock = hr.rock + hr.rock * Math.random() * rndVariation;
				double pPaper = hr.paper + hr.paper * Math.random()* rndVariation;
				double pSicissors = hr.scissors + hr.scissors * Math.random()* rndVariation;
				if (debug) {
					out.println("R:" + pRock + "\tP:" + pPaper + "\tS:"
							+ pSicissors);
				}
				if (pRock > pPaper & pRock > pSicissors) {
					cCurrent = RPS.Paper;
				}
				if (pPaper > pSicissors & pPaper > pRock) {
					cCurrent = RPS.Scissors;
				}
				if (pSicissors > pRock & pSicissors > pPaper) {
					cCurrent = RPS.Rock;
				}
			}
			// Ask the human to answer
			out.print("Make your move. (R|P|S): ");
			RPS pCurrent = RPS.Nothing;

			String input;
			if (autoplay < 1) {
				input = s.nextLine();
			} else {
				input = "R";
				// input = RPS.values()[(int) Math.round(Math.random() *
				// 2)].toString();
				autoplay--;
			}
			if (input.length() > 0) {
				switch (input.toUpperCase().charAt(0)) {
				case 'R':
					pCurrent = RPS.Rock;
					if (hr != null)
						hr.rock++;
					break;
				case 'P':
					pCurrent = RPS.Paper;
					if (hr != null)
						hr.paper++;
					break;
				case 'S':
					pCurrent = RPS.Scissors;
					if (hr != null)
						hr.scissors++;
					break;
				case 'H':
					for (int i = 0; i < history.size(); i++) {
						out.println(history.get(i).toString());
					}
					break;
				case '!':
					rndVariation = Integer.parseInt(input.substring(1));
					break;
				case 'D':
					debug = ! debug;
					break;
				}
			}
			if (pCurrent != RPS.Nothing) {
				out.println("You picked: " + pCurrent.toString());
				out.println("I picked: " + cCurrent.toString());
				// Check results.
				if (pCurrent == cCurrent) {
					out.println("Draw!");
					ties++;
				} else {
					if (pCurrent == RPS.Rock && cCurrent == RPS.Scissors
							|| pCurrent == RPS.Paper && cCurrent == RPS.Rock
							|| pCurrent == RPS.Scissors
							&& cCurrent == RPS.Paper) {
						out.println("You win!");
						pScore++;
					} else {
						out.println("I win!");
						cScore++;
					}
				}
				// save the data
				cHist.add(cCurrent);
				pHist.add(pCurrent);

				// say the score
				out.println("Humans:    " + pScore);
				out.println("Computers: " + cScore);
				out.println("Ties:      " + ties);
			}
		}
	}

	public static RPSHist getHistRecord() {
		// History repeats itself.
		// So do people.
		if (cHist.size() < 4)
			return null;
		List<RPS> smallComputerHist = cHist.subList(cHist.size() - 4,
				cHist.size() - 1);
		List<RPS> smallPlayerHist = pHist.subList(pHist.size() - 4,
				pHist.size() - 1);
		int i = 0;
		while (i < history.size()) {
			if (history.get(i).match(smallPlayerHist, smallComputerHist)) {
				return history.get(i);
			}
			i++;
		}
		RPSHist r = new RPSHist();
		r.computerHist = new LinkedList<RPS>();
		r.playerHist = new LinkedList<RPS>();
		for (int copyIndex = 0; copyIndex < smallComputerHist.size(); copyIndex++) {
			r.computerHist.add(smallComputerHist.get(copyIndex));
			r.playerHist.add(smallPlayerHist.get(copyIndex));
		}
		history.add(r);
		return r;
	}
}
